import json
import os
import sys
import logging

try:
    __file__
except NameError as e:
    from whereis import mymain
    rootdir = mymain()
else:
    rootdir = os.path.dirname(os.path.dirname(__file__))


sys.path.insert(0, rootdir)
from lib.bashlog import getlogger
from lib.tracemore import get_exc_plus
from minsix import open
from minsix import input
from lib.config import Config
sys.path.pop(0)

logger = logging.getLogger('wordson.data')

cfg = Config()


class Data(object):
    _ins = None

    def __new__(cls):
        if cls._ins is None:
            ins = super(Data, cls).__new__(cls)

            # load the words data
            fullpath = os.path.normpath(os.path.abspath(os.path.join(rootdir, cfg.data_cfg)))
            logger.info('full data config path: %s', fullpath)
            if not os.path.exists(fullpath):
                logger.warning('%s not found. create a empty one', fullpath)
                cls.makeconfig(fullpath, [])

            ins._data_file = open(fullpath, 'r+', encoding='utf-8')
            ins.attr = json.load(ins._data_file)
            path = os.path.dirname(fullpath)    # it's abs path
            ins._data_path = path

            # path is abspath, so this is abspath
            known = set(os.path.normpath(os.path.join(path, attr['path'])) for attr in ins.attr)
            for dirpath, dirnames, filenames in os.walk(path):
                for eachfile in filenames:
                    # seems path is abspath, then this is abspath
                    filepath = os.path.join(dirpath, eachfile)
                    if not filepath.endswith('.json') or filepath == fullpath:
                        logger.debug('%s is not a json file or is config file', eachfile)
                        continue
                    assert os.path.isabs(filepath)
                    if filepath not in known:
                        relpath = os.path.relpath(filepath, path)
                        name = os.path.split(filepath)[-1]
                        name = os.path.splitext(name)[0]
                        ins.attr.append({
                            'name': name,
                            'path': path,
                            'language': None,
                            'category': None
                        })

            # load the saving
            fullpath = os.path.normpath(os.path.abspath(os.path.join(rootdir, cfg.save_cfg)))
            if not os.path.exists(fullpath):
                logger.warning('%s not exists, create', fullpath)
                cls.makeconfig(fullpath, [])
            ins._save_file = open(fullpath, 'r+', encoding='utf-8')
            ins.saved = json.load(ins._save_file)

            for dirpath, dirnames, filenames in os.walk(os.path.dirname(fullpath)):
                for eachfile in filenames:
                    filepath = os.path.join(dirpath, eachfile)
                    if not filepath.endswith('.json') or filepath == fullpath:
                        logger.debug('%s is not a json file or is config file', eachfile)
                        continue
                    pass

            cls._ins = ins

        return cls._ins


    def get_cates(self):
        '''get_cates() -> set
        get all categories
        None in set means unknown'''
        return {each['category'] for each in self.attr}

    def get_langs(self):
        '''get_langs -> set
        get all languages
        None in set means unknown'''
        return {each['language'] for each in self.attr}

    def get_cates_under(self, language):
        '''get_cates_under(language) -> set
        get all categories under language
        language=None means unknown language'''
        logger.debug('language %s', language)
        result = set()
        for each in self.attr:
            if each['language'] == language:
                result.add(each['category'])
        return result

    def get_name_path_under(self, language, category):
        '''get_name_path_under(language, category) -> set'''
        logger.debug('language %s; category %s', language, category)
        result = set()
        for each in self.attr:
            if each['language'] == language and each['category'] == category:
                result.add((each['name'], os.path.join(self._data_file.name, each['path'])))
        return result

    def set_current(self, path):
        with open(path, 'r', encoding='utf-8'):
            self.source = json.load(path)

    @staticmethod
    def makeconfig(path, obj):
        dirname = os.path.dirname(path)
        if os.path.exists(dirname):
            if not os.path.isdir(dirname):
                msg = '%s exists and is not a folder'
                logger.critical(msg)
                raise ValueError(msg)
        else:
            os.makedirs(dirname)
        with open(path, 'w', encoding='utf-8') as f:
            json.dump(obj, f, indent=4, ensure_ascii=False)

if __name__ == '__main__':
    getlogger(logger, logging.DEBUG)
    data = Data()

    print(data.get_cates())
    lang = data.get_langs()
    for each in lang:
        for cate in data.get_cates_under(each):
            print(each, cate, ':')
            for name, path in data.get_name_path_under(each, cate):
                print(name, path)
